package we.dispatcher;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import we.common.CDebug;
import we.config.CConstant;
import we.exception.ReadingPacketException;
import we.session.CAttachment;

public class CReadHandler implements Runnable
{

    private BlockingQueue<SelectionKey> in;
    private ByteBuffer buffer;

    public CReadHandler(BlockingQueue<SelectionKey> in)
    {
        this.in = in;
        buffer = ByteBuffer.allocateDirect(CConstant.MAX_MESSAGE_LENGTH);
    }

    @Override
    public void run()
    {
        SelectionKey key = null;
        SocketChannel clientChannel = null;
        int numRead = 0;
        while (true)
        {
            try
            {
                try
                {
                    //   Debug.trace("try read..");   
                    key = in.take();
                    if (key != null && key.isValid())
                    {
                        {
                            //  Debug.trace("read ready..");                        
                            CAttachment attachment = (CAttachment) key.attachment();
                            CPacketReader reader = attachment.reader;
                            if (!reader.idle)
                            {
                                continue;
                            }
                            reader.idle = false;
                            clientChannel = (SocketChannel) key.channel();
                            buffer.clear();
                            numRead = clientChannel.read(buffer);
                            if (numRead == -1)
                            {
                                //     Debug.trace("Disconnect...");
                                CCoreServer.instance().CloseChannel(key);
                                continue;
                            }

                            buffer.flip();

                            while (buffer.hasRemaining())
                            {
//                                byte n = buffer.get();      
//                                pro.put(n);
//                                CDebug.trace(Thread.currentThread().getName() + " read : " + n);
                                //Debug.trace("instance.put((byte)" + n + ");");
                                
                                reader.put(buffer.get());

                                if (reader.checkCompletedPackage())
                                {
                                    //   Debug.trace("----------");
                                    CCoreServer.instance().getHandler().MessageReceived(attachment.session, reader);
                                    reader.clearAll();
                                }
                            }

                            reader.idle = true;

                        }
                    }

                } catch (ReadingPacketException ex)
                {
                    Logger.getLogger(CReadHandler.class.getName()).log(Level.SEVERE, null, ex);
                    CCoreServer.instance().CloseChannel(key);
                } catch (IOException innerIOE)
                {
                    if (innerIOE.getMessage().contains("An existing connection was forcibly closed"))
                    {
                        CDebug.Trace(this, "Exception expected, yay.");
                        CCoreServer.instance().CloseChannel(key);
                    } else
                    {
                        throw innerIOE;
                    }

                } catch (InterruptedException ex)
                {
                    Logger.getLogger(CReadHandler.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (Exception ex)
            {
                Logger.getLogger(CReadHandler.class.getName()).log(Level.SEVERE, null, ex);                
                CCoreServer.instance().CloseChannel(key);
            }
        }
    }
}
